<?php
namespace api\service;

use api\service\interfaces\IOrderService;
use herosphp\bean\Beans;
use herosphp\core\Loader;
use herosphp\core\Log;
use herosphp\utils\AjaxResult;
use payment\utils\SerialNumberUtils;
use user\service\interfaces\IUserLogService;

Loader::import('api.service.interfaces.IOrderService');

/**
 * 订单服务接口实现
 * @author Liuyi<liuy@pvc123.com>
 */
class OrderService implements IOrderService
{
    /**
     * 订单支付， 支付流程：
     * 1. 判断买家的余额够不够支付
     * 2. 买家的余额和可用余额均减少
     * 3. 卖家余额增加，冻结余额增加，可用余额不变
     * 4. 记录日志和流水
     * @param $orderNo 订单编号
     * @param $payUserId 付款人ID(买家)
     * @param $payeeUserId 收款人ID(卖家)
     * @param $amount 发生金额
     * @return AjaxResult
     */
    public function orderPay($orderNo, $payUserId, $payeeUserId, $amount)
    {
        $userService = Beans::get('user.user.service');
        $buyer = $userService->getItem($payUserId);
        $seller = $userService->getItem($payeeUserId);
        if ( !$this->checkUserPermission($buyer, $message) ) {
            return new AjaxResult(AjaxResult::OP_FAILURE, $message);
        }
        //检测可用余额
        if ( $buyer['usable'] < $amount || $buyer['balance'] < $amount ) {
            return new AjaxResult(AjaxResult::OP_FAILURE, "可用余额不足");
        }

        //买家可用和余额减少,买家累计消费额增加
        $userService->beginTransaction();
        $step1 = $userService->reduce(array('usable', 'balance', 'total_cost'), array($amount, $amount, -$amount), $payUserId);
        if ( $step1 ) {
            $step2 = $userService->increase(array('out_frozen', 'balance'), array($amount, $amount), $payeeUserId);
            if ( $step2 ) {
                //2. 添加支付流水
                $logService = Beans::get('user.userLog.service');
                $logData = array(
                    'app_id' => getAPPID(),
                    'userid' => $payUserId,
                    'username' => $buyer['username'],
                    'type' => IUserLogService::LOG_TYPE_PAY,
                    'atype' => '-',
                    'serial_no' => SerialNumberUtils::generate('L'),
                    'order_no' => $orderNo,
                    'amount' => $amount,
                    'balance' => $buyer['balance']-$amount,
                    'usable' => $buyer['usable']-$amount,
                    'out_frozen' => $buyer['out_frozen'],
                    'addtime' => date('Y-m-d H:i:s')
                );
                $logService->add($logData);
                //添加卖家日志
                $logData['userid'] = $payeeUserId;
                $logData['username'] = $seller['username'];
                $logData['atype'] = '+';
                $logData['balance'] = $seller['balance'] + $amount;
                $logData['usable'] = $seller['usable'];
                $logData['out_frozen'] = $seller['out_frozen'] + $amount;
                $logService->add($logData);

                $userService->commit(); //事务提交
                return new AjaxResult(AjaxResult::OP_SUCCESS, LANG('DEAL_SUCCESS'));
            } else {
                $userService->rollback(); //事务回滚
            }
        }
        return new AjaxResult(AjaxResult::OP_FAILURE, LANG('DEAL_FAILD'));

    }

    /**
     * 确认收货，业务流程：
     * 1. 查找对应的订单支付流水，获取支付金额
     * 2. 将卖家资金解冻,可用余额增加
     * 3. 生成确认收货流水
     * @param $orderNo 订单编号
     * @param $payUserId 付款人ID
     * @param $payeeUserId 收款人ID
     * @return AjaxResult
     */
    public function orderConfirm($orderNo, $payUserId, $payeeUserId)
    {
        $logService = Beans::get('user.userLog.service');
        $userService = Beans::get('user.user.service');
        $conditions = array('order_no' => $orderNo, 'userid' => $payeeUserId);
        if ( $logService->count($conditions) > 1 ) {
            return new AjaxResult(AjaxResult::OP_FAILURE, '订单已确认收货，请勿重复确认');
        }
        $log = $logService->getItem($conditions);
        if ( empty($log) ) {
            return new AjaxResult(AjaxResult::OP_FAILURE, '找不到订单的支付流水');
        }

        $userService->beginTransaction(); //开启事务
        $res = $userService->increase(array('usable', 'out_frozen'), array($log['amount'], -$log['amount']), $payeeUserId);
        if ( $res ) {
            //更新用户最后一次交易时间
            $userService->set('last_trade_time', date('Y-m-d H:i:s'), $payeeUserId);
            $userService->set('last_trade_time', date('Y-m-d H:i:s'), $payUserId);
            //生成流水
            $payee = $userService->getItem($payeeUserId);
            $logData = array(
                'app_id' => getAPPID(),
                'userid' => $payeeUserId,
                'username' => $payee['username'],
                'type' => IUserLogService::LOG_TYPE_CONFIRM,
                'atype' => '',
                'serial_no' => SerialNumberUtils::generate('L'),
                'order_no' => $orderNo,
                'amount' => $log['amount'],
                'balance' => $payee['balance'],
                'usable' => $payee['usable'],
                'out_frozen' => $payee['out_frozen'],
                'addtime' => date('Y-m-d H:i:s')
            );
            if ( $logService->add($logData) ) {
                $userService->commit();
                return new AjaxResult(AjaxResult::OP_SUCCESS, LANG('DEAL_SUCCESS'));
            } else {
                $userService->rollback();
            }

        }

        return new AjaxResult(AjaxResult::OP_FAILURE, LANG('DEAL_FAILD'));
    }

    /**
     * 确认银行流水(线下支付专用)
     * 1. 一笔订单对应多笔流水
     * 2. 一笔流水对应多笔订单
     * @param $serialIds 流水ID数组(默认是一笔订单多笔支付流水)
     * @param $orderNO 订单编号
     *  @param $orderAmount 订单金额
     * @return AjaxResult
     */
    public function confirmFundLog(array $serialIds, $orderNO, $orderAmount)
    {
        if ( func_num_args() < 3 ) {
            return new AjaxResult(AjaxResult::OP_FAILURE, LANG('DEAL_FAILD'));
        }
        $bankLogService = Beans::get('payment.bankLog.service');
        $confirmAmount = $orderAmount; //待确认金额
        $result = true;
        $logs = $bankLogService->getItems(array('id' => array('$in' => $serialIds)));
        if ( empty($logs) ) {
            return AjaxResult::fail("确认流水失败，找不到相应的流水.");
        }
        //判断流水总金余额是否小于订单金额
        $logTotalAmount = 0;
        foreach ( $logs as $value ) {
            $logTotalAmount += ($value['amount']-$value['confirmed_money']);
        }
        if ( $logTotalAmount < $orderAmount ) {
            return AjaxResult::fail("确认流水失败，流水总金额小于订单金额");
        }
        foreach ( $logs as $log ) {

            if ( $confirmAmount <= 0 ) break;
            $logUsable = $log['amount'] - $log['confirmed_money']; //流水可用余额
            if ( $logUsable >= $confirmAmount ) { //如果单笔流水的可用余额大于订单总金额，则只确认一笔流水
                $data = array();
                if ( $log['amount'] == $confirmAmount ) $data['is_confirmed'] = 1;
                $data['order_no'] = $log['order_no'].", {$orderNO}";
                $data['confirmed_money'] = $log['confirmed_money'] + $confirmAmount;
                $result = $result && $bankLogService->update($data, $log['id']);
                break;

            } else {
                $data = array();
                $data['is_confirmed'] = 1;
                $data['order_no'] = $log['order_no'].", {$orderNO}";
                $data['confirmed_money'] = $log['amount'];
                $result = $result && $bankLogService->update($data, $log['id']);
                $confirmAmount -= $logUsable;
            }
        }

        if ( $result ) {
            return new AjaxResult(AjaxResult::OP_SUCCESS, LANG('DEAL_SUCCESS'));
        } else {
            Log::info("确认流水失败，更新数据库失败.");
            return new AjaxResult(AjaxResult::OP_FAILURE, LANG('DEAL_FAILD'));
        }

    }

    /**
     * @see \api\service\interfaces\IOrderService::getFundFlows
     */
    public function getFundFlows($userid, $conditions=array())
    {
        $userService = Beans::get('user.user.service');
        $bankLogService = Beans::get('payment.bankLog.service');

        $user = $userService->getItem($userid);
        $conditions['is_offline'] = 1;
        $conditions['virtual_account'] = $user['virtual_account'];
        $items = $bankLogService->where($conditions)->find();
        $resultVo = new AjaxResult(AjaxResult::OP_SUCCESS, LANG('DEAL_SUCCESS'));
        $resultVo->putItems($items);
        return $resultVo;
    }

    /**
     * 检测用户操作权限
     * @param $user 用户
     * @param $message 错误信息
     * @return bool
     */
    protected function checkUserPermission($user, &$message) {
        if ( $user['ischecked'] != 2 ) {
            $message = LANG('DEAL_FAILD').', '.LANG('USER_NOT_CHECKED');
            return false;
        }
        if ( $user['sign_status'] != 1 ) {
            $message = LANG('DEAL_FAILD').', '.LANG('USER_NOT_SIGNED');
            return false;
        }
        return true;
    }

}
